package com.tbit.uqbike.webmanager.business.maintain_performance.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.NumberUtil;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.tbit.common.constant.PerformanceTypeConstant;
import com.tbit.common.entity.view.PageResult;
import com.tbit.config.datasource.DataSource;
import com.tbit.uqbike.constant.MachineAbnormalConstant;
import com.tbit.uqbike.manager.exception.BaseException;
import com.tbit.uqbike.object.pojo.AccountConfigExt;
import com.tbit.uqbike.object.pojo.AccountUser;
import com.tbit.uqbike.object.pojo.PowerChangeMonitorConfig;
import com.tbit.uqbike.object.pojo.Region;
import com.tbit.uqbike.object.pojo.statistics.DispatchLog;
import com.tbit.uqbike.object.pojo.tag.Tag;
import com.tbit.uqbike.object.pojo.tag.TagNew;
import com.tbit.uqbike.object.value.LoginInfo;
import com.tbit.uqbike.service.base.RedisService;
import com.tbit.uqbike.service.business.AccountConfigExtService;
import com.tbit.uqbike.service.business.AccountUserService;
import com.tbit.uqbike.service.business.PowerChangeMonitorConfigService;
import com.tbit.uqbike.service.business.tag.TagService;
import com.tbit.uqbike.service.business.tag.impl.TagServiceNew;
import com.tbit.uqbike.webmanager.business.maintain_performance.constant.PerformanceBizType;
import com.tbit.uqbike.webmanager.business.maintain_performance.constant.PerformanceRuleType;
import com.tbit.uqbike.webmanager.business.maintain_performance.dao.log.DispatchPerformanceDao;
import com.tbit.uqbike.webmanager.business.maintain_performance.object.DispatchPerformance;
import com.tbit.uqbike.webmanager.business.maintain_performance.object.DispatchPerformanceLog;
import com.tbit.uqbike.webmanager.business.maintain_performance.object.dto.config.DispatchPerformanceConfig;
import com.tbit.uqbike.webmanager.business.maintain_performance.object.dto.rule.MoveDistanceRule;
import com.tbit.uqbike.webmanager.business.maintain_performance.object.dto.rule.TagSolvedRule;
import com.tbit.uqbike.webmanager.business.maintain_performance.object.dto.rule.UnusedTimeBasedRule;
import com.tbit.uqbike.webmanager.business.maintain_performance.object.dto.stat.*;
import com.tbit.uqbike.webmanager.dao.core.AccountUserDao;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author <a href="mailto:zheng.zebiao@tbit.com.cn">zb</a>
 * @since 2025/2/18
 */
@Slf4j
@Service
public class DispatchPerformanceService extends ServiceImpl<DispatchPerformanceDao, DispatchPerformance> {
    @Autowired
    PowerChangeMonitorConfigService powerChangeMonitorConfigService;
    @Autowired
    AccountUserService accountUserService;
    @Autowired
    AccountUserDao accountUserDao;
    @Autowired
    DispatchPerformanceLogService performanceLogService;
    @Autowired
    TagServiceNew tagService;
    @Autowired
    RedisService redisService;
    @Autowired
    PerformanceRuleGroupService ruleGroupService;
    @Autowired
    AccountConfigExtService accountConfigExtService;

    /**
     * 检查是否开启绩效开关
     *
     * @param accountId 区域id
     * @return true 开启，false 未开启
     */
    public boolean checkSwitch(Integer accountId) {
        AccountConfigExt performanceSwitch = accountConfigExtService.getByAccountIdAndType(accountId, "dispatch_performance");
        if (performanceSwitch == null || Objects.equals(performanceSwitch.getParamValue(), "0")) {
            return false;
        }
        return true;
    }

    public PageResult<DispatchPerformanceDetail> queryPerformanceDetailPage(DispatchPerformanceDetailReq req) {
        req.buildDispatchSqlCondition(powerChangeMonitorConfigService::getById);

        // 查询绩效分页
        Page<DispatchPerformanceDetail> details = PageHelper.startPage(req.getPageNo(), req.getPageSize());
        getBaseMapper().queryDetailPage(req);
        details.close();

        PowerChangeMonitorConfig monitorConfig = Optional.ofNullable(powerChangeMonitorConfigService.getById(req.getAccountId()))
                .orElseGet(() -> new PowerChangeMonitorConfig().putDefaultValue(req.getAccountId()));
        Map<Integer, AccountUser> accountUserMap = Optional.ofNullable(accountUserService.getByType(req.getAccountId(), false))
                .map(x -> x.stream().collect(Collectors.toMap(AccountUser::getAccountUserId, Function.identity(), (v1, v2) -> v1)))
                .orElse(Collections.emptyMap());
        if (CollUtil.isNotEmpty(details)) {
            for (DispatchPerformanceDetail detail : details) {
                // 补充运维人员信息
                AccountUser accountUser = accountUserMap.get(detail.getAccountUserId());
                if (accountUser != null) {
                    detail.setAccountUserName(accountUser.getName());
                    detail.setAccountUserPhone(accountUser.getPhone());
                }

                // 计算闲置区间
                detail.setIdleRange(monitorConfig.matchDispatchRange(detail.getIdleTime()));

                // 审核状态(excel导出用)
                detail.setAuditStatus(
                        (Objects.equals(detail.getAuditorId(), 1) ? "系统" : "人工") + "-" +
                                (Objects.equals(detail.getIsValid(), 1) ? "有效" : (Objects.equals(detail.getIsValid(), 2) ? "审核中" : "无效"))
                );
            }
        }
        return PageResult.convertPage(details.toPageInfo());
    }

    public List<PerformanceChartPerDateDetail> queryStatChart(Integer accountId, Date startTime, Date endTime, Integer accountUserId, Integer machineType, Integer isValid, LoginInfo loginInfo) {
        List<PerformanceChartDo> chartDos = getBaseMapper().queryPerformanceChart(accountId, startTime, endTime, accountUserId, machineType, isValid);
        List<AccountUser> accountUserList = new ArrayList<>();
        if (accountUserId == null){
            accountUserList.addAll((List<AccountUser>) accountUserService.getParentsAccountUser(accountId, loginInfo).getData());
        }else {
            accountUserList.add(accountUserService.getAccountUserById(accountUserId));
        }
        Map<Integer, String> accountUserMap = Optional.ofNullable(accountUserList)
                .map(x -> x.stream().collect(Collectors.toMap(AccountUser::getAccountUserId, AccountUser::getName, (v1, v2) -> v1)))
                .orElse(Collections.emptyMap());
        return PerformanceChartPerDateDetail.fromDo(accountUserMap, chartDos, LocalDateTimeUtil.of(startTime).toLocalDate(), LocalDateTimeUtil.of(endTime).toLocalDate());
    }

    public PageResult<PerformanceOverviewResp> queryOverviewPage(PerformanceOverviewReq req) {
        try (Page<PerformanceOverviewResp> page = PageHelper.startPage(req.getPageNo(), req.getPageSize())) {
            if (req.getType() == 0) { // 按人员查
                getBaseMapper().queryOverviewPageByUser(req);

                // 填充运维人员信息
                Map<Integer, AccountUser> accountUserMap = Optional.ofNullable(accountUserService.getByType(req.getAccountId(), false))
                        .map(x -> x.stream().collect(Collectors.toMap(AccountUser::getAccountUserId, Function.identity(), (v1, v2) -> v1)))
                        .orElse(Collections.emptyMap());
                if (CollUtil.isNotEmpty(page)) {
                    for (PerformanceOverviewResp overview : page) {
                        AccountUser accountUser = accountUserMap.get(overview.getAccountUserId());
                        if (accountUser != null) {
                            overview.setAccountUserName(accountUser.getName());
                            overview.setAccountUserPhone(accountUser.getPhone());
                        }
                    }
                }
            } else { // 按分区查
                getBaseMapper().queryOverviewPageByRegion(req);

                // 填充分区信息
                Map<Integer, Region> regionMap = accountUserDao.getRegionId(req.getAccountId()).stream()
                        .collect(Collectors.toMap(Region::getRegionId, Function.identity()));
                if (CollUtil.isNotEmpty(page)) {
                    for (PerformanceOverviewResp overview : page) {
                        Region region = regionMap.get(overview.getRegionId());
                        if (region != null) {
                            overview.setRegionName(region.getRegionName());
                        }
                    }
                }
            }
            return PageResult.convertPage(page.toPageInfo());
        }
    }

    /**
     * 更新绩效
     *
     * @param performanceId 绩效ID
     * @param performance   绩效值
     * @param remark        备注
     */
    @DS(DataSource.LOG)
    @Transactional
    public void updatePerformance(Long performanceId, BigDecimal performance, String remark) {
        DispatchPerformance update = getById(performanceId);
        BigDecimal oldPerformance = update.getPerformance();
        update.setPerformanceId(performanceId);
        update.setPerformance(performance);
        update.setRemark(remark);
        update.setPerformanceDetail("人工修改绩效: 总绩效" + NumberUtil.toStr(performance, true));
        update.setPerformanceType(PerformanceTypeConstant.MANUAL);
        updateById(update);
        // 计算新旧绩效差值，用于新增一条绩效日志记录dispatch_performance_log
        BigDecimal subPerformance = performance.subtract(oldPerformance);
        if (subPerformance.compareTo(BigDecimal.ZERO) == 0) {
            return;
        }
        // 记录绩效日志  业务类型设置为人工， 绩效为新旧绩效的差值
        DispatchPerformanceLog log = new DispatchPerformanceLog();
        BeanUtil.copyProperties(update, log, "remark");
        log.setPerformance(subPerformance);
        log.setRuleType(PerformanceRuleType.MANUAL.getValue());
        log.setRemark("MANAGER-人工修改绩效: " + NumberUtil.toStr(oldPerformance, true) + " -> " + NumberUtil.toStr(performance, true));
        performanceLogService.save(log);
    }

    /**
     * 插入零绩效记录
     *
     * @param dispatchLogDb 调度记录
     */
    @DS(DataSource.LOG)
    @Transactional()
    public void insertZeroPerformance(DispatchLog dispatchLogDb) {
        DispatchPerformance dispatchPerformance = new DispatchPerformance();
        dispatchPerformance.setDispatchLogId(dispatchLogDb.getDispatchLogId());
        dispatchPerformance.setPerformance(BigDecimal.ZERO);
        dispatchPerformance.setPerformanceDetail("");
        dispatchPerformance.setAccountId(dispatchLogDb.getAccountId());
        Date dispatchTime = dispatchLogDb.getDispatchTime();
        int hour = DateUtil.hour(dispatchTime, true);
        if (hour >= 0 && hour < 6) {
            dispatchPerformance.setDispatchInterval(1);
        } else if (hour >= 6 && hour < 12) {
            dispatchPerformance.setDispatchInterval(2);
        } else if (hour >= 12 && hour < 18) {
            dispatchPerformance.setDispatchInterval(3);
        } else if (hour >= 18 && hour < 24) {
            dispatchPerformance.setDispatchInterval(4);
        }
        if (dispatchLogDb.getFirstOrderTime() != null) {
            dispatchPerformance.setFirstOrderDuration(
                    (int) DateUtil.between(DateUtil.parse(dispatchLogDb.getFirstOrderTime()),
                            dispatchLogDb.getFinishTime(),
                            DateUnit.MINUTE)
            );
        }
        dispatchPerformance.setOrderCountAfter24Hour(0);
        dispatchPerformance.setRemark("无效改有效系统自动生成;");
        save(dispatchPerformance);
    }

    /**
     * 删除调度绩效记录
     *
     * @param dispatchLogId 调度记录ID
     */
    @DS(DataSource.LOG)
    @Transactional
    public void removePerformance(Integer dispatchLogId) {
        DispatchPerformance dispatchPerformance = getOne(Wrappers.<DispatchPerformance>query()
                .eq(DispatchPerformance.Fields.dispatchLogId, dispatchLogId));
        if (dispatchPerformance == null) {
            return;
        }
        if (BigDecimal.ZERO.compareTo(dispatchPerformance.getPerformance()) != 0){
            // 增加一条绩效日志详情记录 dispatch_performance_log
            DispatchPerformanceLog log = createNegateDispatchPerformanceLog(dispatchPerformance);
            performanceLogService.save(log);
        }
        removeById(dispatchPerformance.getPerformanceId());
    }

    /**
     * 批量删除调度绩效记录
     *
     * @param dispatchLogIds 调度记录ID列表
     */
    @DS(DataSource.LOG)
    @Transactional
    public void removePerformance(List<Integer> dispatchLogIds) {
        List<DispatchPerformance> performanceList = list(Wrappers.<DispatchPerformance>query()
                .in(DispatchPerformance.Fields.dispatchLogId, dispatchLogIds));
        if (performanceList == null || performanceList.isEmpty()) {
            return;
        }
        List<DispatchPerformanceLog> logs = new ArrayList<>();
        performanceList
                .stream()
                .filter(dispatchPerformance -> BigDecimal.ZERO.compareTo(dispatchPerformance.getPerformance()) != 0)
                .forEach(dispatchPerformance -> logs.add(createNegateDispatchPerformanceLog(dispatchPerformance)));
        if (!logs.isEmpty()){
            performanceLogService.insertBatch(logs);
        }
        removeBatchByIds(performanceList.stream().map(DispatchPerformance::getPerformanceId).collect(Collectors.toList()));
    }

    private DispatchPerformanceLog createNegateDispatchPerformanceLog(DispatchPerformance dispatchPerformance) {
        DispatchPerformanceLog log = new DispatchPerformanceLog();
        BeanUtil.copyProperties(dispatchPerformance, log, "remark");
        log.setPerformance(dispatchPerformance.getPerformance().negate());// 取绩效负数
        log.setRuleType(PerformanceRuleType.MANUAL.getValue());
        log.setRemark("MANAGER-MANUAL-手动修改调度日志从有效改为无效-自动添加");
        return log;
    }

    private DispatchPerformanceLog setPerformance(DispatchPerformance dp, BigDecimal performanceValue){
        dp.setPerformance(performanceValue);
        dp.setPerformanceDetail("manager-修改有效性同时修改绩效");
        // 设置人工修改的标志，被人工修改之后，后面的绩效计算不再考虑这条记录。
        dp.setPerformanceType(PerformanceTypeConstant.MANUAL);
        // 记录绩效日志  业务类型设置为人工， 绩效为新旧绩效的差值
        DispatchPerformanceLog log = new DispatchPerformanceLog();
        BeanUtil.copyProperties(dp, log, "remark");
        log.setPerformance(performanceValue);
        log.setPerformanceDetail("manager-人工修改绩效值");
        log.setRuleType(PerformanceRuleType.MANUAL.getValue());
        log.setRemark("manager-修改有效性同时修改绩效: " + NumberUtil.toStr(performanceValue, true));
        return log;
    }

    private DispatchPerformanceLog reSetPerformance(DispatchPerformance dp, BigDecimal performanceValue){
        BigDecimal oldPerformance = dp.getPerformance();
        // 需要修改绩效值
        dp.setPerformance(performanceValue);
        dp.setPerformanceDetail("manager-修改有效性同时修改绩效");
        // 设置人工修改的标志，被人工修改之后，后面的绩效计算不再考虑这条记录。
        dp.setPerformanceType(PerformanceTypeConstant.MANUAL);
        // 计算新旧绩效差值，用于新增一条绩效日志记录dispatch_performance_log
        BigDecimal subPerformance = performanceValue.subtract(oldPerformance);
        if (subPerformance.compareTo(BigDecimal.ZERO) != 0) {
            // 记录绩效日志  业务类型设置为人工， 绩效为新旧绩效的差值
            DispatchPerformanceLog log = new DispatchPerformanceLog();
            BeanUtil.copyProperties(dp, log, "remark");
            log.setPerformance(subPerformance);
            log.setPerformanceDetail("manager-人工修改绩效值");
            log.setRuleType(PerformanceRuleType.MANUAL.getValue());
            log.setRemark("manager-修改有效性同时修改绩效: " + NumberUtil.toStr(oldPerformance, true) + " -> " + NumberUtil.toStr(performanceValue, true));
            return log;
        }
        return null;
    }

    /**
     * 生成调度绩效记录
     *
     * @param dispatchLog
     * @param performanceValue
     */
    @DS(DataSource.LOG)
    @Transactional
    public void generatePerformance(DispatchLog dispatchLog, BigDecimal performanceValue) {
        if (performanceValue != null && performanceValue.compareTo(BigDecimal.ZERO) < 0) {
            throw new BaseException("绩效值不能小于0");
        }
        // 获取绩效记录
        DispatchPerformance dp = getOne(Wrappers.<DispatchPerformance>query()
                .eq(DispatchPerformance.Fields.dispatchLogId, dispatchLog.getDispatchLogId())
        );
        if (dp == null) {
            log.info("[调度绩效] 生成新绩效记录, 调度记录id: {},performanceValue:{}", dispatchLog.getDispatchLogId(), performanceValue);
            dp = createDispatchPerformance(dispatchLog);
            List<DispatchPerformanceLog> performanceLogs = new ArrayList<>();
            if (performanceValue != null){
                DispatchPerformanceLog log = setPerformance(dp, performanceValue);
                performanceLogs.add(log);
            }else {
                // 通过规则计算绩效值
                calculatePerformance(dispatchLog, dp, performanceLogs);
            }
            save(dp);
            // 保存绩效日志
            if (!performanceLogs.isEmpty()) {
                // 填充绩效记录id
                Long performanceId = dp.getPerformanceId();
                performanceLogs.forEach(performanceLog -> performanceLog.setPerformanceId(performanceId));
                performanceLogService.insertBatch(performanceLogs);
            }
        }else {
            // 已经存在绩效记录
            if (performanceValue != null) {
                log.info("[调度绩效] 已经存在绩效记录,修改绩效, 调度记录id: {},绩效记录id: {},performanceValue:{}", dispatchLog.getDispatchLogId(), dp.getPerformanceId(), performanceValue);
                DispatchPerformanceLog log = reSetPerformance(dp, performanceValue);
                if (log != null){
                    performanceLogService.save(log);
                }
                updateById(dp);
            }
        }
        clearDispatchPerformanceConfig();
    }

    /**
     * 批量生成调度绩效
     *
     * @param dispatchLogs
     * @param performanceValue
     */
    @DS(DataSource.LOG)
    @Transactional
    public void generatePerformance(List<DispatchLog> dispatchLogs, BigDecimal performanceValue) {
        if (dispatchLogs == null || dispatchLogs.isEmpty()) {
            return;
        }
        if (performanceValue != null && performanceValue.compareTo(BigDecimal.ZERO) < 0) {
            throw new BaseException("绩效值不能小于0");
        }
        // 获取绩效记录
        List<Integer> dispatchLogIds = dispatchLogs.stream().map(DispatchLog::getDispatchLogId).collect(Collectors.toList());
        List<DispatchPerformance> dps = list(Wrappers.<DispatchPerformance>query().in(DispatchPerformance.Fields.dispatchLogId, dispatchLogIds));
        if (dps != null && !dps.isEmpty()) {
            if (performanceValue != null) {
                log.info("[调度绩效] 批量生成调度绩效,已经存在绩效记录,修改绩效,绩效记录size: {},performanceValue:{}", dps.size(), performanceValue);
                List<DispatchPerformanceLog> performanceLogs = new ArrayList<>();
                // 更新dps
                dps.forEach(dp -> {
                    DispatchPerformanceLog log = reSetPerformance(dp, performanceValue);
                    if (log != null){
                        performanceLogs.add(log);
                    }
                });
                updateBatchById(dps);
                // 保存绩效日志
                if (!performanceLogs.isEmpty()) {
                    performanceLogService.insertBatch(performanceLogs);
                }
            }
            // 这里要考虑这种情况，dispatchLogIds中有部分有绩效记录，部分没有，或者全部已经有绩效记录
            Set<Integer> hasDpDispatchIds = dps.stream().map(DispatchPerformance::getDispatchLogId).collect(Collectors.toSet());
            if (hasDpDispatchIds.size() < dispatchLogIds.size()) {
                // 存在部分没有绩效记录的，需要生成新的调度绩效记录
                dispatchLogs = dispatchLogs.stream()
                        .filter(dl -> !hasDpDispatchIds.contains(dl.getDispatchLogId()))
                        .collect(Collectors.toList());
            }
            if(hasDpDispatchIds.size() == dispatchLogIds.size()){
                // 已经全部有对应的绩效记录，不需要再处理了
                dispatchLogs.clear();
            }
        }
        log.info("[调度绩效] 批量生成调度绩效, 调度记录id: {}", dispatchLogIds);
        // dispatchLogs是最终要处理的记录，根据performanceValue是否传值来生成对应的绩效
        if (!dispatchLogs.isEmpty()){
            // 新增绩效记录
            List<DispatchPerformance> performances = new ArrayList<>();
            List<DispatchPerformanceLog> performanceLogs = new ArrayList<>();
            dispatchLogs.forEach(dispatchLog ->{
                DispatchPerformance dp = createDispatchPerformance(dispatchLog);
                if (performanceValue != null) {
                    DispatchPerformanceLog log = setPerformance(dp, performanceValue);
                    performanceLogs.add(log);
                }else {
                    // 通过规则计算绩效
                    calculatePerformance(dispatchLog, dp, performanceLogs);
                }
                performances.add(dp);
            });
            if (!performances.isEmpty()){
                // 批量保存绩效
                saveBatch(performances);
                // <调度记录id，调度绩效实体>
                Map<Integer, DispatchPerformance> performancesMap = performances.stream().collect(Collectors.toMap(DispatchPerformance::getDispatchLogId, Function.identity()));
                if (!performanceLogs.isEmpty()) {
                    // 填充绩效记录id
                    performanceLogs.forEach(performanceLog -> performanceLog.setPerformanceId(performancesMap.get(performanceLog.getDispatchLogId()).getPerformanceId()));
                    // 保存绩效日志
                    performanceLogService.insertBatch(performanceLogs);
                }
            }
        }
        clearDispatchPerformanceConfig();
    }

    /**
     * 计算调度绩效
     */
    private void calculatePerformance(DispatchLog dl, DispatchPerformance dp, List<DispatchPerformanceLog> performanceLogs) {
        DispatchPerformanceConfig config = getDispatchPerformanceConfig(dl);

        BigDecimal performance = BigDecimal.ZERO;
        StringBuilder detail = new StringBuilder();

        // 基础绩效
        if (config.getBasic() != null && config.getBasic().getEnabled()) {
            log.info("[调度绩效] 调度记录id: {}, 适用基础绩效", dp.getDispatchLogId());
            BigDecimal validPerf = config.getBasic().getValidPerformance();
            performance = performance.add(validPerf);
            detail.append("基础绩效: ")
                    .append(NumberUtil.toStr(validPerf))
                    .append(";");
            DispatchPerformanceLog performanceLog = new DispatchPerformanceLog();
            BeanUtil.copyProperties(dp, performanceLog, "performance", "performanceDetail", "remark");
            performanceLog.setPerformance(validPerf);
            performanceLog.setPerformanceDetail("基础绩效: " + NumberUtil.toStr(validPerf) + ";");
            performanceLog.setRuleType(PerformanceRuleType.BASIC.getValue());
            performanceLog.setRemark("MANAGER-BASIC-基础绩效");
            performanceLogs.add(performanceLog);
        }

        // 闲置时长
        if (config.getUnusedTimeBased() != null && config.getUnusedTimeBased().getEnabled()) {
            for (UnusedTimeBasedRule subRule : config.getUnusedTimeBased().getSubRules()) {
                if (subRule.getUnusedTime().match(dl.getIdleTime())) {
                    log.info("[调度绩效] 调度记录id: {}, 适用闲置时长绩效, 闲置时长: {}h", dp.getDispatchLogId(), subRule.getUnusedTime());
                    performance = performance.add(subRule.getPerformance());
                    detail.append("闲置时长绩效: ")
                            .append(NumberUtil.toStr(subRule.getPerformance()))
                            .append("(")
                            .append(subRule.getUnusedTime())
                            .append("小时);");
                    DispatchPerformanceLog performanceLog = new DispatchPerformanceLog();
                    BeanUtil.copyProperties(dp, performanceLog, "performance", "performanceDetail", "remark");
                    performanceLog.setPerformance(subRule.getPerformance());
                    performanceLog.setPerformanceDetail("闲置时长绩效: " + NumberUtil.toStr(subRule.getPerformance()) + "(" + subRule.getUnusedTime() + "小时);");
                    performanceLog.setRuleType(PerformanceRuleType.UNUSED_TIME.getValue());
                    performanceLog.setRemark("MANAGER-UNUSED_TIME-闲置时长");
                    performanceLogs.add(performanceLog);
                    break;
                }
            }
        }

        // 调度距离
        if (config.getDistanceBased() != null && config.getDistanceBased().getEnabled()) {
            for (MoveDistanceRule subRule : config.getDistanceBased().getSubRules()) {
                if (subRule.getDistanceMeter().match(dl.getDistance())) {
                    log.info("[调度绩效] 调度记录id: {}, 适用调度距离绩效, 调度距离: {}m", dp.getDispatchLogId(), subRule.getDistanceMeter());
                    performance = performance.add(subRule.getPerformance());
                    detail.append("调度距离绩效: ")
                            .append(NumberUtil.toStr(subRule.getPerformance()))
                            .append("(")
                            .append(subRule.getDistanceMeter())
                            .append("米);");
                    DispatchPerformanceLog performanceLog = new DispatchPerformanceLog();
                    BeanUtil.copyProperties(dp, performanceLog, "performance", "performanceDetail", "remark");
                    performanceLog.setPerformance(subRule.getPerformance());
                    performanceLog.setPerformanceDetail("调度距离绩效: " + NumberUtil.toStr(subRule.getPerformance()) + "(" + subRule.getDistanceMeter() + "米);");
                    performanceLog.setRuleType(PerformanceRuleType.DISTANCE.getValue());
                    performanceLog.setRemark("MANAGER-DISTANCE-调度距离");
                    performanceLogs.add(performanceLog);
                    break;
                }
            }
        }

        // 车辆标签
        if (config.getTagSolved() != null && config.getTagSolved().getEnabled()) {
            log.info("[调度绩效] 调度记录id: {}, 适用车辆标签绩效", dp.getDispatchLogId());
            List<TagNew> tags = getTags(dl.getMachineId()); // 从缓存获取车辆标签

            for (TagSolvedRule subRule : config.getTagSolved().getSubRules()) {
                for (Tag tag : tags) {
                    if (subRule.getTagIds().contains(tag.getId())) {
                        performance = performance.add(subRule.getPerformance());
                        detail.append("车辆标签绩效: ")
                                .append(NumberUtil.toStr(subRule.getPerformance()))
                                .append("(标签: ")
                                .append(tag.getName())
                                .append(");");
                        DispatchPerformanceLog performanceLog = new DispatchPerformanceLog();
                        BeanUtil.copyProperties(dp, performanceLog, "performance", "performanceDetail", "remark");
                        performanceLog.setPerformance(subRule.getPerformance());
                        performanceLog.setPerformanceDetail("车辆标签绩效: " + NumberUtil.toStr(subRule.getPerformance()) + "(标签:" + tag.getName() + ");");
                        performanceLog.setRuleType(PerformanceRuleType.MACHINE_TAG.getValue());
                        performanceLog.setRemark("MANAGER-MACHINE_TAG-车辆标签：" + tag.getName());
                        performanceLogs.add(performanceLog);
                        break;
                    }
                }
            }
        }

        dp.setPerformance(performance);
        dp.setPerformanceDetail(detail.toString());
    }

    private DispatchPerformance createDispatchPerformance(DispatchLog dispatchLog) {
        DispatchPerformance dp = new DispatchPerformance();
        dp.setDispatchLogId(dispatchLog.getDispatchLogId());
        dp.setAccountId(dispatchLog.getAccountId());
        Date dispatchTime = dispatchLog.getDispatchTime();
        dp.setOrderCountAfter24Hour(0);
        List<TagNew> tags = getTags(dispatchLog.getMachineId());
        if (!tags.isEmpty()) {
            dp.setBeforeTag(tags.stream()
                    .map(Tag::getName)
                    .collect(Collectors.joining(",")));
        }
        // 挪车前状态
        List<Integer> abnormalCache = getAbnormalCache(dispatchLog.getMachineId());
        if (!abnormalCache.isEmpty()) {
            StringBuilder abnormalTypes = new StringBuilder();
            for (Integer abnormalType : abnormalCache) {
                abnormalTypes.append(MachineAbnormalConstant.parse(abnormalType))
                        .append(",");
            }
            dp.setBeforeStatus(abnormalTypes.substring(0, abnormalTypes.length() - 1));
        }
        // 调度时段
        int hour = DateUtil.hour(dispatchTime, true);
        if (hour >= 0 && hour < 6) {
            dp.setDispatchInterval(1);
        } else if (hour >= 6 && hour < 12) {
            dp.setDispatchInterval(2);
        } else if (hour >= 12 && hour < 18) {
            dp.setDispatchInterval(3);
        } else if (hour >= 18 && hour < 24) {
            dp.setDispatchInterval(4);
        }
        return dp;
    }

    private List<TagNew> getTags(Integer machineId) {
        return tagService.getTags(machineId);
    }

    /**
     * 获取缓存车辆异常，供后续调度绩效使用
     *
     * @param machineId 车辆id
     * @return 异常类型列表
     */
    public List<Integer> getAbnormalCache(Integer machineId) {
        String value = redisService.get(ABNORMAL_KEY + machineId);
        if (value != null) {
            return Arrays.stream(value.split(","))
                    .map(Integer::parseInt)
                    .collect(Collectors.toList());
        }
        return Collections.emptyList();
    }

    private DispatchPerformanceConfig getDispatchPerformanceConfig(DispatchLog dl) {
        DispatchPerformanceConfig dispatchPerformanceConfig = accountDispatchConfig.get(dl.getAccountId());
        if (dispatchPerformanceConfig == null){
            dispatchPerformanceConfig = ruleGroupService.selectBizPerformanceConfig(dl.getAccountId(), DispatchPerformanceConfig::fromRaw, PerformanceBizType.DISPATCH);
            accountDispatchConfig.put(dl.getAccountId(), dispatchPerformanceConfig);
        }
        return dispatchPerformanceConfig;
    }

    private void clearDispatchPerformanceConfig(){
        accountDispatchConfig.clear();
    }

    public static final String ABNORMAL_KEY = "maintainPerformance:dispatch:abnormal:";
    private final ConcurrentHashMap<Integer,DispatchPerformanceConfig> accountDispatchConfig = new ConcurrentHashMap<>();
}
